## handler (controller) connecting widgets and models.
#
#  @author Thomas Lehmann
#  @file   Handler.py
#
# Thanks to:
#  - http://effbot.org/tkinterbook (widgets)
#  - http://www.daniweb.com/code/snippet594.html (listbox)
#  - http://www.daniweb.com/code/snippet852.html (mouse wheel)
#
import Tkinter as tk
import Widgets

from Base           import *
from ListBoxHandler import *

class RootHandler(BaseHandler):
    def __init__(self, factory, widget):
        BaseHandler.__init__(self, factory, widget)

class FrameHandler(BaseHandler):
    def __init__(self, factory, widget):
        BaseHandler.__init__(self, factory, widget)

    def initialize(self, wid, attributes):
        self.wid = wid
        self.factory.registerHandler(wid, self)

## very simply handle for a label.
class LabelHandler(BaseHandler):
    def __init__(self, factory, widget):
        BaseHandler.__init__(self, factory, widget)
        self.image = None

    def initialize(self, wid, attributes):
        self.wid = wid
        self.factory.registerHandler(wid, self)

    def setValue(self, value, row = 0, column = 0):
        self.widget["text"] = value

    def getValue(self, row = 0, column = 0):
        return self.widget["text"]

class LabelFrameHandler(BaseHandler):
    def __init__(self, factory, widget):
        BaseHandler.__init__(self, factory, widget)

class CanvasHandler(BaseHandler):
    def __init__(self, factory, widget):
        BaseHandler.__init__(self, factory, widget)

    def initialize(self, wid, attributes):
        self.wid = wid
        self.factory.registerHandler(self.wid, self)

class ButtonHandler(BaseHandler):
    def __init__(self, factory, widget):
        BaseHandler.__init__(self, factory, widget)
        self.widget["command"] = self.clicked

    def initialize(self, wid, attributes):
        self.wid = wid
        self.factory.registerHandler(self.wid, self)

    def clicked(self):
        for model in self.models:
            model.updateValue(self.wid, None, "activated")

class CheckbuttonHandler(BaseHandler):
    def __init__(self, factory, widget):
        BaseHandler.__init__(self, factory, widget)
        self.variable = tk.StringVar()
        self.widget["variable"] = self.variable
        self.widget["command"]  = self.clicked

    def initialize(self, wid, attributes):
        self.wid = wid
        self.factory.registerHandler(wid, self)

        if attributes.has_key("value"):
            self.variable.set(attributes["value"])

    def clicked(self):
        #print "Checkbutton '%s' has been clicked (%s)" % (self.wid, self.variable.get())
        for model in self.models:
            model.updateValue(self.wid, self.variable.get(), "changed")

    def setAttribute(self, attr, value):
        BaseHandler.setAttribute(self, attr, value)

    def setValue(self, value, row = -1, column = -1):
        self.variable.set(value)

    def getValue(self, row = -1, column = -1):
        return self.variable.get()

class RadiobuttonHandler(BaseHandler):
    def __init__(self, factory, widget):
        BaseHandler.__init__(self, factory, widget)
        self.widget["command"] = self.clicked

    def initialize(self, wid, attributes):
        self.wid = wid
        self.factory.registerHandler(wid, self)
        self.widget["value"] = wid

        if self.parent:
            if self.parent.variables.has_key("radio"):
                self.widget["variable"] = self.parent.variables["radio"]
            else:
                variable = tk.StringVar()
                self.widget["variable"]        = variable
                self.parent.variables["radio"] = variable

        if attributes.has_key("value"):
            self.parent.variables["radio"].set(wid)

    def clicked(self):
        #print "Radiobutton '%s' has been clicked" % (self.wid)
        for model in self.models:
            model.updateValue(self.wid, self.parent.variables["radio"].get(), "changed")

    def setValue(self, value = None, row = -1, column = -1):
        self.parent.variables["radio"].set(self.wid)

class EntryHandler(BaseHandler):
    def __init__(self, factory, widget):
        BaseHandler.__init__(self, factory, widget)
        self.variable = tk.StringVar()
        self.variable.trace_variable('w', self.traceVariable)
        self.widget["textvariable"] = self.variable

    def initialize(self, wid, attributes):
        self.wid = wid
        self.factory.registerHandler(wid, self)

    def traceVariable(self, name, index, mode):
        for model in self.models:
            model.updateValue(self.wid, self.variable.get(), "changed")

    ## tyring to change an attribute of the widget
    def setAttribute(self, attr, value):
        BaseHandler.setAttribute(self, attr, value)

    ## changing the current text of the widget
    def setValue(self, value, row = 0, column = 0):
        self.variable.set(value)

    ## evaluating the current text of the widget
    def getValue(self, value, row = 0, column = 0):
        return self.variable.get()

class TextHandler(BaseHandler):
    def __init__(self, factory, widget):
        BaseHandler.__init__(self, factory, widget)

class ScaleHandler(BaseHandler):
    def __init__(self, factory, widget):
        BaseHandler.__init__(self, factory, widget)
        self.variable = tk.IntVar()
        self.variable.trace_variable('w', self.traceVariable)
        self.widget["variable"] = self.variable

    def initialize(self, wid, attributes):
        self.wid = wid
        self.factory.registerHandler(wid, self)

    def traceVariable(self, name, index, mode):
        #print "Scale '%s' has been changed to %d" % (self.wid, self.variable.get())
        for model in self.models:
            model.updateValue(self.wid, self.variable.get(), "changed")

    def setValue(self, value, row, column):
        self.variable.set(value)

class MenuHandler(BaseHandler):
    def __init__(self, factory, widget):
        BaseHandler.__init__(self, factory, widget)
        self.variables = {}

    def initialize(self, wid, attributes):
        self.wid = wid
        self.factory.registerHandler(wid, self)

    def addSeparator(self):
        self.widget.add_separator()

    def addCascade(self, label, handler, attributes):
        for name in [ "id", "type", "title"]:
            if attributes.has_key(name):
                del attributes[name]

        attributes["menu"  ] = handler.widget
        attributes["label" ] = label
        self.widget.add_cascade(attributes)

    def addCommand(self, label, handler, attributes):
        for name in [ "id", "type", "title"]:
            if attributes.has_key(name):
                del attributes[name]

        attributes["command"] = handler.onMenu
        attributes["label"  ] = label
        self.widget.add_command(attributes)

    def addCheckbutton(self, label, handler, attributes):
        assert attributes.has_key("id")
        variable = tk.StringVar()
        self.variables[attributes["id"]] = variable

        if attributes.has_key("value"):
            variable.set(attributes["value"])

        for name in [ "id", "type", "title", "value"]:
            if attributes.has_key(name):
                del attributes[name]

        attributes["command"  ] = handler.onMenu
        attributes["label"    ] = label
        attributes["variable" ] = variable
        self.widget.add_checkbutton(attributes)

    def onMenu(self):
        value = None
        if self.parent.variables.has_key(self.wid):
            value = self.parent.variables[self.wid].get()

        for model in self.models:
            model.updateValue(self.wid, value, "activated")

class ScrollbarHandler(BaseHandler):
    def __init__(self, factory, widget):
        BaseHandler.__init__(self, factory, widget)

    def initialize(self, wid, attributes):
        self.wid = wid
        self.factory.registerHandler(wid, self)

        target = None
        if attributes.has_key("refid"):
            target = self.factory.handler[attributes["refid"]].widget
        else:
            return

        if self.widget["orient"] == "vertical":
            target     ["yscrollcommand"] = self.widget.set
            self.widget["command"       ] = target.yview

        elif self.widget["orient"] == "horizontal":
            target     ["xscrollcommand"] = self.widget.set
            self.widget["command"       ] = target.xview

class PackHandler(BaseHandler):
    def __init__(self, factory, widget):
        BaseHandler.__init__(self, factory, widget)
        self.defaults           = {}
        self.defaults["expand"] = "yes"
        self.defaults["fill"]   = "both"
        self.defaults["side"]   = "top"

    def initialize(self, options):
        theOptions = self.defaults
        for key, value in options.items():
            theOptions[key] = value

        self.widget.pack(theOptions)
        self.parent.packed = True

class BindHandler(BaseHandler):
    def __init__(self, factory, widget):
        BaseHandler.__init__(self, factory, widget)
        self.options = None

    def initialize(self, options):
        assert options.has_key("id")
        assert options.has_key("sequence")
        assert len(options) == 2

        sequence = "<"+options["sequence"]+">"
        self.widget.bind(sequence, self.event)
        self.options = dict(options)

    def event(self, event):
        for model in self.parent.models:
            model.event(self.parent.wid, self.options["id"])
